#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>

#include "../../common/include/filesystem.h"
#include "../databaseADT/databaseADT.h"
#include "../include/queries.h"
#include "../../common/include/common.h"
#include "../../common/include/general.h"

/*DatabaseADT singleton*/
databaseADT db = NULL;
static int mkdatabase(void);

/*Static functions prototypes for x's queue*/
void freeDirQ(void *ptr);
void *cpyDirQ(void *ptr);
void freeUsrQ(void *ptr);
void *cpyUsrQ(void *ptr);
void freeFifoQ(void *ptr);
void *cpyFifoQ(void *ptr);
void freeLogQ(void *ptr);
void *cpyLogQ(void *ptr);
void *cpyIntQ(void *ptr);
void freeIntQ(void *ptr);

void freedatabase(void)
{
    FreeDatabaseADT(db);
}

static int
mkdatabase(void)
{
    int ret;
    char *path = "./database.db";
    char *schema = "./schema.sql";
    FILE *errLog = NULL;

    if ( (errLog = fopen("error.log", "w")) == NULL )
    {
        fprintf(stderr, "error.log couldn't be opened\n");
        return 0;
    }

    if ( (NewDatabaseADT(&db, path, errLog)) != DB_SUCCESS )
    {
        fprintf(stderr, "NewDatabaseADT failed\n");
        return 0;
    }

    ret = DBBuildDatabase(db, schema);
    if ( ret != DB_SUCCESS && ret != DB_ALREADY_EXISTS)
    {
        fprintf(stderr, "DBBuildDatabase failed\n");
        return 0;
    }

    return 1;

}

DB_ERR
addDir(const char *dir)
{
    databaseADT db;

    if ((db = getdb()) == NULL)
        return DB_INTERNAL_ERROR;

    return DBaddDir(db, dir);
}

DB_ERR
addFifoDir(const char *fifo, const char *dir)
{
    databaseADT db;

    if ((db = getdb()) == NULL)
        return DB_INTERNAL_ERROR;

    return DBaddFifoDir(db, fifo, dir);
}

DB_ERR
addUser(const char *user, const char *fifo)
{
    databaseADT db;

    if ((db = getdb()) == NULL)
        return DB_INTERNAL_ERROR;

    return DBaddUser(db, user, fifo);
}

DB_ERR
addLog(const char *fifo, const char *action)
{
    databaseADT db;

    if ((db = getdb()) == NULL)
        return DB_INTERNAL_ERROR;

    return DBaddLog(db, fifo, action);
}

DB_ERR
DBconnect(const char *user)
{
    databaseADT db;

    if ((db = getdb()) == NULL)
        return DB_INTERNAL_ERROR;

    return DBconnectUser(db, user);
}

DB_ERR
deleteOnline(void)
{
    databaseADT db;

    if ((db = getdb()) == NULL)
        return DB_INTERNAL_ERROR;

    return DBdeleteOnline(db);
}

DB_ERR
disconnectFifo(const char *fifo)
{
    databaseADT db;

    if ((db = getdb()) == NULL)
        return DB_INTERNAL_ERROR;

    return DBdisconnectFifo(db, fifo);
}

DB_ERR
removeDirByFifo(const char *fifo, const char *dir)
{
    databaseADT db;

    if ((db = getdb()) == NULL)
        return DB_INTERNAL_ERROR;

    return DBremoveDirByFifo(db, fifo, dir);
}

DB_ERR
disconnect(const char *user)
{
    databaseADT db;

    if ((db = getdb()) == NULL)
        return DB_INTERNAL_ERROR;

    return DBdisconnectUser(db, user);
}

databaseADT
getdb(void)
{
    if (db == NULL)
        if (!mkdatabase())
            return NULL;

    return db;
}

queueADT
listDirPerUser(const char *user)
{
    int ret;
    queueADT queue;
    int i = 1;
    databaseADT db;

    if ((db = getdb()) == NULL)
        return NULL;

    if ((queue = newQueue(cpyDirQ, freeDirQ)) == NULL)
        return;

    ret = DBgetDirPerUserQueue(db, queue, user);

    switch (ret)
    {
            case DB_SUCCESS:
                break;

            default:
                printf("Database error\n");
                break;

    }

    return queue;
}

queueADT
qLast10(char *user)
{
    int ret;
    queueADT queue;
    int i = 1;
    char log[MAX_LOG_LEN] = {0};
    databaseADT db;

    if ((db = getdb()) == NULL)
        return NULL;

    if ((queue=newQueue(cpyLogQ, freeLogQ)) == NULL)
        return;

    if (user)
        ret = DBgetLast10User(db, queue, user);
    else
        ret = DBgetLast10(db, queue);
    switch (ret)
    {
            case DB_SUCCESS:
                break;

            default:
                printf("Database error\n");
                break;

    }

    return queue;
}


queueADT
listDir(void)
{
    int ret;
    queueADT queue;
    int i = 1;
    char dirName[MAX_DIR_LEN] = {0};
    databaseADT db;

    if ((db = getdb()) == NULL)
        return NULL;

    if ((queue=newQueue(cpyDirQ, freeDirQ)) == NULL)
        return;

    ret = DBgetDirQueue(db, queue);

    switch (ret)
    {
            case DB_SUCCESS:
                break;

            default:
                printf("Database error\n");
                break;

    }

    return queue;
}

queueADT updateIDs(const int id, const char *dir)
{
    int ret;
    queueADT queue;
    int i = 1;
    databaseADT db;

    if ((db = getdb()) == NULL)
        return NULL;

    if ((queue=newQueue(cpyIntQ, freeIntQ)) == NULL)
        return;

    ret = DBgetUpdateIDs(db, queue, id, dir);

    switch (ret)
    {
            case DB_SUCCESS:
                break;

            default:
                printf("Database error\n");
                break;
    }

    return queue;

}

queueADT
listUpdate(const char *fifo, const char *dir)
{
    int ret;
    queueADT queue;
    int i = 1;
    databaseADT db;

    if ((db = getdb()) == NULL)
        return NULL;

    if ((queue=newQueue(cpyFifoQ, freeFifoQ)) == NULL)
        return;

    ret = DBgetUpdateQueue(db, queue, fifo, dir);

    switch (ret)
    {
            case DB_SUCCESS:
                break;

            default:
                printf("Database error\n");
                break;
    }

    return queue;
}

int
userID(const char *user)
{
    int ret;
    int id = -1;
    databaseADT db;

    if ((db = getdb()) == NULL)
        return -1;

    ret = DBgetUserID(db, user, &id);

    switch (ret)
    {
            case DB_SUCCESS:
                break;

            default:
                printf("Database error\n");
                break;
    }

    return id;
}


queueADT
listUsr(void)
{
    int ret;
    queueADT queue;
    int i = 1;
    char userName[MAX_USER_LEN] = {0};
    databaseADT db;

    if ((db = getdb()) == NULL)
        return NULL;

    if ((queue=newQueue(cpyUsrQ, freeUsrQ)) == NULL)
        return;

    ret = DBgetUserQueue(db, queue);

    switch (ret)
    {
            case DB_SUCCESS:
                break;

            default:
                printf("Database error\n");
                break;

    }

    return queue;
}

void *
cpyIntQ(void *ptr)
{
    void *ret;
    ret = malloc(sizeof(int));
    memcpy(ret, ptr, sizeof(int));
    return ret;
}

void
freeIntQ(void *ptr)
{
    if (ptr != NULL)
        free(ptr);

    return;
}

void *
cpyDirQ(void *ptr)
{
    return (void *)strdup((char *)ptr);
}

void
freeDirQ(void *ptr)
{
    if (ptr != NULL)
        free(ptr);

    return;
}

void *
cpyUsrQ(void *ptr)
{
    return (void *)strdup((char *)ptr);
}

void
freeUsrQ(void *ptr)
{
    if (ptr != NULL)
        free(ptr);

    return;
}

void *
cpyFifoQ(void *ptr)
{
    return (void *)strdup((char *)ptr);
}

void
freeFifoQ(void *ptr)
{
    if (ptr != NULL)
        free(ptr);

    return;
}

void *
cpyLogQ(void *ptr)
{
    return (void *)strdup((char *)ptr);
}

void
freeLogQ(void *ptr)
{
    if (ptr != NULL)
        free(ptr);

    return;
}
